/*
	Copyright (C) 2010 Salil Bhagurkar

	This file is part of k3

	k3 is free software: you can redistribute it and/or modify
	it under the terms of the GNU Lesser General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	k3 is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public License
	along with k3.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef _FS_H_
#define _FS_H_

/*Notes:

*/


/*Flags for both enumerator and listener:*/

#define RES_TASK 1 //Wake me up for giving children or when they come
#define RES_CHILD 2 //I will give children or call me when they come
#define RES_READ 4 //Wake me/call me when resources are available
#define RES_WRITE 8 //Wake me/call me when i can write my intended amount of data


/*Enumerator: One who enumerates the children of an fs node*/
struct enumerator {
	u32 flags;
	struct fs *owner;
	struct fs *task; //The task that is waiting to enumerate the resource when required
	int (*enumerate)(struct fs *this);
	int (*enumerate_read)(struct fs *this);
	int (*enumerate_write)(struct fs *this);
	struct enumerator *next, *prev;
};

/*One who listens to appearing children of an fs node*/
struct listener {
	u32 flags;
	struct fs *owner;
	struct fs *task; //The task that is listening to the resource data
	int (*notify)(struct fs *this, struct fs *child); //Notify when a child appears
	int (*notify_read)(struct fs *this); //Notify when the required resources are available
	int (*notify_write)(struct fs *this); //Notify when the required space is available
	struct listener *next, *prev;
};

#define SYSTEM_RESOURCE_WAIT_READ 1 //Resource access management is active
#define SYSTEM_RESOURCE_WAIT_WRITE 2
#define SYSTEM_CONCURRENT_WAIT_READ 4 //Concurrent access management is active
#define SYSTEM_CONCURRENT_WAIT_WRITE 8

struct fs;
/*Interface solely for the kernel*/
struct fs_system {
	u32 flags;
	u32 read_count; //The data available from the system of this node
	u32 read_semaphore; //Number of simultaneous users allowed to read/write from the resource
	u32 write_count; //Amount of data that can be written
	u32 write_semaphore; //Number of simultaneous users allowed to write to the resource
	struct fs *fs; //Reverse pointer to the fs. This will indicate the original node when the node is moved
	int (*read)(struct fs *referrer, struct fs *this, struct buffer *buf, u32 offset, u32 count);
	int (*write)(struct fs *referrer, struct fs *this, struct buffer *buf, u32 offset, u32 count);
	int (*rename)(struct fs *referrer, struct fs *this, char *new_name);
	struct enumerator *enumerators, *enumeratorstail;
	struct listener *listeners, *listenerstail;
};

#define FS_SYSTEM_RESOURCE_INIT .read_count = 0, .read_semaphore = 0, .write_count = 0, .write_semaphore = 0
#define INIT_FS_SYSTEM_RESOURCE(n) (n)->read_count = (n)->read_semaphore = (n)->write_count = (n)->write_semaphore = 0
#define FS_SYSTEM_EVENT_INIT .enumerators = NULL, .enumeratorstail = NULL, .listeners = NULL, .listenerstail = NULL
#define INIT_FS_SYSTEM_EVENT(n) (n)->enumerators = (n)->enumeratorstail = NULL; (n)->listeners = (n)->listenerstail = NULL


#define FSFLAGS_TYPE_MASK 7

#define FSFLAGS_DEVICE 0 //The system is not a standard data interface system and
	//is a kernel interface to some driver or some other shit
#define FSFLAGS_DATA 2 //Simple data node
#define FSFLAGS_DEVICE_DRIVER 3 //Driver that is able to bring in devices
#define FSFLAGS_VMDRV 5 //This is a vm driver and child execution should not be done for it


#define FSFLAGS_MODE_MASK 24
#define FSFLAGS_MODE_READ 8
#define FSFLAGS_MODE_WRITE 16

#define FS_NAME_LEN 32
#define MAX_FS_NAME_LEN (20*FS_NAME_LEN)

struct data {
	u32 length;
	void *data;
};

/*The fs node that holds data and may have clients and servers*/
struct fs {
	u32 flags; //Defines the type of this fs node
	char name[FS_NAME_LEN];
	struct fs_system *system; //Operations on the node
	struct buffer buf;
	struct fs *parent, *links, *linkstail; //File system links
	struct fs *next, *prev; //This node is a part of a linked list
};

#define LINK_INIT .parent = NULL, .links = NULL, .linkstail = NULL, .next = NULL, .prev = NULL
#define INIT_LINK(n) (n)->parent = NULL; (n)->links = NULL; (n)->linkstail = NULL; (n)->next = NULL; (n)->prev = NULL

#define DATA_INIT .buf = {.data = NULL, .len = 0, .alloc_len = 0}
#define INIT_DATA(n) (n)->buf.data = NULL; (n)->buf.len = 0; (n)->buf.alloc_len = 0

#define FS_INIT .flags = 0, .system = NULL, DATA_INIT, LINK_INIT
#define INIT_FS(n) (n)->flags = 0; (n)->system = NULL; INIT_DATA(n); INIT_LINK(n)

int fs_system_generic_read(struct fs *referrer, struct fs *this, struct buffer *buf, u32 offset, u32 count);
int fs_system_generic_write(struct fs *referrer, struct fs *this, struct buffer *buf, u32 offset, u32 count);
int fs_system_generic_rename(struct fs *referrer, struct fs *this, char *new_name);

int fs_transfer_data(struct fs *fs1, struct fs *fs0);


int fs_server(struct fs *x, struct fs *k);
int fs_client(struct fs *x, struct fs *k);
int fs_elink(struct fs *x, struct fs *k);

int fs_link(struct fs *x, struct fs *link);
int fs_link_vmdrv(struct fs *x, struct fs *link);
int fs_unlink(struct fs *link);
int fs_unlink_recurse(struct fs *first_node);
int fs_read(struct fs *referrer, struct fs *x, struct buffer *buf, u32 offset, u32 count);
int fs_write(struct fs *referrer, struct fs *x, struct buffer *buf, u32 offset, u32 count);

struct fs *fsparse_get(const char *s);
struct fs *fsparse_get_relative(struct fs *from, const char *s);
struct fs_system *fs_create_system(u32 flags,
	int (*read)(struct fs *referrer, struct fs *this, struct buffer *buf, u32 offset, u32 count),
	int (*write)(struct fs *referrer, struct fs *this, struct buffer *buf, u32 offset, u32 count),
	int (*rename)(struct fs *referrer, struct fs *this, char *new_name), struct fs *fs);
struct fs *fs_create(u32 flags, char *name);

int fs_rename(struct fs *referrer, struct fs *x, char *new_name);

int fs_move(struct fs *reparent, struct fs *from);
int fs_copy(struct fs *reparent, struct fs *from);
int fs_copy_get_new(struct fs *reparent, struct fs *from, struct fs **new_node);

struct fs_link {
	struct fs *to;
	char *path;
};



char *fsparse_get_path(char *s, struct fs *node);





/*fsres functions---------------------------------------------------------*/
#define RW_R 0
#define RW_W 1

int fsres_attach_enumerator(struct fs *x, struct enumerator *enumerator);
int fsres_attach_listener(struct fs *x, struct listener *listener);


int fsres_get_read_count(u32 *read_count, struct fs *x);
int fsres_get_write_count(u32 *write_count, struct fs *x);

int fsres_wait_on_read(struct fs *on, struct fs *owner);
int fsres_wait_on_write(struct fs *on, struct fs *owner);

int fsres_update_resource_read(struct fs *x, u32 read_count);
int fsres_update_resource_write(struct fs *x, u32 write_count);

int fsres_rw_enumerators(struct fs *x, int rw);
int fsres_rw_listeners(struct fs *x, int rw);

/*Child resource functions*/

int fsres_add_enumerator(struct fs *x, struct fs *owner, int (*enumerate)(struct fs *this));
int fsres_add_listener(struct fs *x, struct fs *owner, int (*notify)(struct fs *this, struct fs *child));

int fsres_child_enumerators(struct fs *x);
int fsres_child_listeners(struct fs *x, struct fs *child);



/*Run*/
int fsrun(struct fs *start_fs);



/**
Debug functions:
*/
void __fs_tree(struct fs *node);
void __fs_print(struct fs *x);


#endif
